package com.colin.library.view.custom;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.colin.library.view.R;
import com.colin.library.view.help.ViewLogHelp;

/**
 * Created by Colin on 2017/3/1.
 * 第一步：重写构造方法（如果有自定义属性），onFinishInflate()，onMeasure()，onLayout()
 * 第二步：处理滑动事件
 */

public class PullRefreshLayout extends ViewGroup {

    private View mHeader;                                   //头部
    private View mFooter;                                   //尾部
    private TextView text_pull_refresh_header;              //头部文字
    private ImageView image_pull_refresh_header;            //头部箭头
    private ProgressBar progressbar__pull_refresh_header;   //头部进度
    private TextView text_pull_refresh_footer;              //尾部文字
    private ProgressBar progressbar_pull_refresh_footer;    //尾部精度

    private int mLayoutContentHeight;                       //记录内容视图部分的实际总高度
    private int mEffectiveHeaderHeight;                     //头部高度
    private int mEffictiveFooterHeight;                     //尾部高度
    private int mLastMoveY;                                 //最后移动的尾部Y
    private int mLastYIntercept;                                //
    private int lastChildIndex;                             //最后一个控件

    private Status mStatus = Status.NORMAL;                 //默认状态

    private void updateStatus(Status status) {
        mStatus = status;
    }

    private enum Status {
        NORMAL, TRY_REFRESH, REFRESHING, TRY_LOAD_MORE, LOADING;
    }

    /**
     * 接口回调  用于刷新或者加载更过
     */
    public interface OnRefreshListener {
        void refreshFinished();

        void loadMoreFinished();
    }

    private OnRefreshListener mRefreshListener;

    public void addPullRefreshListener(OnRefreshListener mRefreshListener) {
        this.mRefreshListener = mRefreshListener;
    }

    public PullRefreshLayout(Context context) {
        this(context, null, 0);
    }

    public PullRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 当view的所有child从xml中被初始化后调用
     * lastChildIndex记录xml中配置的最后一个child的索引可以获得 view的索引，后面我们将用这个 索引获取到View，来判断footer是否显示
     * 然后还有 addHeader 和 addFooter，就是为 整个layout添加 Header和 Footer，以及初始化 header和footer中的 textview等
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        lastChildIndex = getChildCount() - 1;

        addHeader();
        addFooter();
    }

    /**
     * 添加头部控件
     */
    private void addHeader() {
        mHeader = LayoutInflater.from(getContext()).inflate(R.layout.layout_pull_refresh_header, this, false);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        addView(mHeader, params);

        text_pull_refresh_header = (TextView) findViewById(R.id.text_pull_refresh_header);
        image_pull_refresh_header = (ImageView) findViewById(R.id.image_pull_refresh_header);
        progressbar__pull_refresh_header = (ProgressBar) findViewById(R.id.progressbar__pull_refresh_header);
    }

    /**
     * 初始化尾部控件
     */
    private void addFooter() {
        mFooter = LayoutInflater.from(getContext()).inflate(R.layout.layout_pull_refresh_footer, this, false);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        addView(mFooter, params);
        text_pull_refresh_footer = (TextView) findViewById(R.id.text_pull_refresh_footer);
        progressbar_pull_refresh_footer = (ProgressBar) findViewById(R.id.progressbar_pull_refresh_footer);
    }

    /**
     * 计算所有child的尺寸
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * onLayout在自己或child，的大小和位置发生变化时会被调用。它个主要的作用还是决定这个View应该放在那儿，怎么放。
     * 里面有几个重要的地方： layout 函数 的参数是 ：（left，top，right，bottom）
     * <p>
     * 如果是header，应该摆放在：
     * （0，- header height，header width，0）
     * <p>
     * footer应该摆放在：
     * （0，content height， footer width，content height + footer height）
     * <p>
     * 如果是 ViewGroup 里面的内容，应该摆放在：
     * （0，content height，content width，content height + 当前加进来的child height）
     * <p>
     * 需要注意的是，mLayoutContentHeight 是指所有content的高度，就是所有child加起来的高度，是一个不断累加的值，
     * 添加一个child就添加一些，但是不包括header和footer。
     *
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        //置零，否则同样会因为重复累加得到错误的结果。
        mLayoutContentHeight = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child == mHeader) {// 头视图隐藏在顶端
                child.layout(0, 0 - child.getMeasuredHeight(), child.getMeasuredWidth(), 0);
                mEffectiveHeaderHeight = child.getHeight();
            } else if (child == mFooter) {//尾视图隐藏在layout所有内容视图之后
                child.layout(0, mLayoutContentHeight, child.getMeasuredWidth(), mLayoutContentHeight + child.getMeasuredHeight());
                mEffictiveFooterHeight = child.getHeight();
            } else {// 内容视图根据定义(插入)顺序,按由上到下的顺序在垂直方向进行排列
                child.layout(0, mLayoutContentHeight, child.getMeasuredWidth(), mLayoutContentHeight + child.getMeasuredHeight());
                if (i < getChildCount()) {
                    if (child instanceof ScrollView) {
                        mLayoutContentHeight += getMeasuredHeight();
                        continue;
                    }
                    mLayoutContentHeight += child.getMeasuredHeight();
                }
            }
        }
    }

    /**
     * 需要在这个函数中判断是否应该拦截滑动事件，
     * 例如child是一个ListView，那么它没有滑到头或者没有滑到尾的时候，我们都不应该拦截，
     * ACTION_DOWN和ACTION_UP和不需要拦截，
     * 当事件为 ACTION_MOVE 时，
     * 如果是向下滑动，判断第一个child是否滑倒最上面，如果是，则更新状态为 TRY_REFRESH；
     * 如果是向上滑动，则判断最后一个child是否滑动最底部，如果是，则更新状态为TRY_LOAD_MORE。然后返回 intercept = true。
     * 这样接下来的滑动事件就会传给本类的 onTouchEvent 处理。
     *
     * @param event
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean isInterceptTouchEvent = super.onInterceptTouchEvent(event);


        int y = (int) event.getY();
        ViewLogHelp.e("y==" + String.valueOf(y));
        if (mStatus == Status.REFRESHING || mStatus == Status.LOADING) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 拦截时需要记录点击位置，不然下一次滑动会出错
                mLastMoveY = y;
                ViewLogHelp.e("mLastMoveY==" + String.valueOf(mLastMoveY));
                isInterceptTouchEvent = false;
                break;
            case MotionEvent.ACTION_UP:
                isInterceptTouchEvent = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (y > mLastYIntercept) {//向下滑动
                    View child = getChildAt(0);
                    isInterceptTouchEvent = getRefreshIntercept(child);
                    if (isInterceptTouchEvent) {
                        updateStatus(mStatus.TRY_REFRESH);
                    }
                } else if (y < mLastYIntercept) {//向上滑动
                    View child = getChildAt(lastChildIndex);
                    isInterceptTouchEvent = getLoadMoreIntercept(child);
                    if (isInterceptTouchEvent) {
                        updateStatus(mStatus.TRY_LOAD_MORE);
                    }
                }


                break;
        }
        ViewLogHelp.e("isInterceptTouchEvent-->>" + String.valueOf(isInterceptTouchEvent));
        mLastYIntercept = y;
        return isInterceptTouchEvent;
    }

    /**
     * 处理拦截后的touch事件，我们主要根据滑动的位置来做状态的修改，和属性动画的控制。
     *最大滚动距离，有效距离
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isTouchEvent = super.onTouchEvent(event);
        int y = (int) event.getY();
        ViewLogHelp.e("y==" + String.valueOf(y));
        // 正在刷新或加载更多，避免重复
        if (mStatus == Status.REFRESHING || mStatus == Status.LOADING) {
            return true;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMoveY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int dy = mLastMoveY - y;
                ViewLogHelp.e("dy==" + String.valueOf(dy));
                ViewLogHelp.e("getScrollY==" + getScrollY());
                // 一直在下拉
                if (getScrollY() <= 0 && dy <= 0) {
                    if (mStatus == Status.TRY_LOAD_MORE) {
                        scrollBy(0, dy / 30);
                    } else {
                        scrollBy(0, dy / 3);
                    }
                }
                // 一直在上拉
                else if (getScrollY() >= 0 && dy >= 0) {
                    if (mStatus == Status.TRY_REFRESH) {
                        scrollBy(0, dy / 30);
                    } else {
                        scrollBy(0, dy / 3);
                    }
                } else {
                    scrollBy(0, dy / 3);
                }

                beforeRefreshing();
                beforeLoadMore();
                break;
            case MotionEvent.ACTION_UP:
                // 下拉刷新，并且到达有效长度
                if (getScrollY() <= -mEffectiveHeaderHeight) {
                    releaseWithStatusRefresh();
                    if (mRefreshListener != null) {
                        mRefreshListener.refreshFinished();
                    }
                }
                // 上拉加载更多，达到有效长度
                else if (getScrollY() >= mEffictiveFooterHeight) {
                    releaseWithStatusLoadMore();
                    if (mRefreshListener != null) {
                        mRefreshListener.loadMoreFinished();
                    }
                } else {
                    releaseWithStatusTryRefresh();
                    releaseWithStatusTryLoadMore();
                }
                break;
        }

        mLastMoveY = y;
        ViewLogHelp.e("onTouchEvent-->>" + String.valueOf(isTouchEvent));
        return isTouchEvent;
    }

    /*汇总判断 刷新和加载是否拦截*/
    private boolean getRefreshIntercept(View child) {
        boolean intercept = false;
        if (child instanceof AdapterView) {
            intercept = adapterViewRefreshIntercept(child);
        } else if (child instanceof ScrollView) {
            intercept = scrollViewRefreshIntercept(child);
        } else if (child instanceof RecyclerView) {
            intercept = recyclerViewRefreshIntercept(child);
        }
        return intercept;
    }


    private boolean getLoadMoreIntercept(View child) {
        boolean intercept = false;

        if (child instanceof AdapterView) {
            intercept = adapterViewLoadMoreIntercept(child);
        } else if (child instanceof ScrollView) {
            intercept = scrollViewLoadMoreIntercept(child);
        } else if (child instanceof RecyclerView) {
            intercept = recyclerViewLoadMoreIntercept(child);
        }
        return intercept;
    }
  /*汇总判断 刷新和加载是否拦截*/

    /*具体判断各种View是否应该拦截*/
    // 判断AdapterView下拉刷新是否拦截
    private boolean adapterViewRefreshIntercept(View child) {
        boolean intercept = true;
        AdapterView adapterChild = (AdapterView) child;
        if (adapterChild.getFirstVisiblePosition() != 0 || adapterChild.getChildAt(0).getTop() != 0) {
            intercept = false;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }

    // 判断AdapterView加载更多是否拦截
    private boolean adapterViewLoadMoreIntercept(View child) {
        boolean intercept = false;
        AdapterView adapterChild = (AdapterView) child;
        if (adapterChild.getLastVisiblePosition() == adapterChild.getCount() - 1 &&
                (adapterChild.getChildAt(adapterChild.getChildCount() - 1).getBottom() >= getMeasuredHeight())) {
            intercept = true;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }

    // 判断ScrollView刷新是否拦截
    private boolean scrollViewRefreshIntercept(View child) {
        boolean intercept = false;
        if (child.getScrollY() <= 0) {
            intercept = true;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }

    // 判断ScrollView加载更多是否拦截
    private boolean scrollViewLoadMoreIntercept(View child) {
        boolean intercept = false;
        ScrollView scrollView = (ScrollView) child;
        View scrollChild = scrollView.getChildAt(0);
        if (scrollView.getScrollY() >= (scrollChild.getHeight() - scrollView.getHeight())) {
            intercept = true;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }

    // 判断RecyclerView刷新是否拦截
    private boolean recyclerViewRefreshIntercept(View child) {
        boolean intercept = false;
        RecyclerView recyclerView = (RecyclerView) child;
        if (recyclerView.computeVerticalScrollOffset() <= 0) {
            intercept = true;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }

    // 判断RecyclerView加载更多是否拦截
    private boolean recyclerViewLoadMoreIntercept(View child) {
        boolean intercept = false;
        RecyclerView recyclerView = (RecyclerView) child;
        if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
                >= recyclerView.computeVerticalScrollRange()) {
            intercept = true;
        }
        ViewLogHelp.e("intercept==" + String.valueOf(intercept));
        return intercept;
    }
  /*具体判断各种View是否应该拦截*/


    /*修改header和footer的状态*/

    /**
     * 滑动的距离，最大是header的高度，然后计算旋转角度比例*180，就得到了旋转的角度，然后直接将ImageView的rotation设置旋转角度
     */
    public void beforeRefreshing() {
        //计算旋转角度
        int scrollY = Math.abs(getScrollY());
        scrollY = scrollY > mEffectiveHeaderHeight ? mEffectiveHeaderHeight : scrollY;
        float angle = (float) (scrollY * 1.0 / mEffectiveHeaderHeight * 180);
        image_pull_refresh_header.setRotation(angle);
        if (getScrollY() <= -mEffectiveHeaderHeight) {
            text_pull_refresh_header.setText("松开刷新");
        } else {
            text_pull_refresh_header.setText("下拉刷新");
        }
    }

    public void beforeLoadMore() {
        if (getScrollY() >= mEffectiveHeaderHeight) {
            text_pull_refresh_footer.setText("松开加载更多");
        } else {
            text_pull_refresh_footer.setText("上拉加载更多");
        }
    }

    /**
     * 加载完成隐藏进度条，显示箭头
     */
    public void refreshFinished() {
        scrollTo(0, 0);
        text_pull_refresh_header.setText("下拉刷新");
        progressbar__pull_refresh_header.setVisibility(GONE);
        image_pull_refresh_header.setVisibility(VISIBLE);
        updateStatus(Status.NORMAL);
    }

    public void loadMoreFinished() {
        text_pull_refresh_footer.setText("上拉加载");
        progressbar_pull_refresh_footer.setVisibility(GONE);
        scrollTo(0, 0);
        updateStatus(Status.NORMAL);
    }

    private void releaseWithStatusTryRefresh() {
        scrollBy(0, -getScrollY());
        text_pull_refresh_header.setText("下拉刷新");
        updateStatus(Status.NORMAL);
    }

    private void releaseWithStatusTryLoadMore() {
        scrollBy(0, -getScrollY());
        text_pull_refresh_footer.setText("上拉加载更多");
        updateStatus(Status.NORMAL);
    }

    /**
     * 松开手时隐藏箭头，显示进度条
     */
    private void releaseWithStatusRefresh() {
        scrollTo(0, -mEffectiveHeaderHeight);
        progressbar__pull_refresh_header.setVisibility(VISIBLE);
        image_pull_refresh_header.setVisibility(GONE);
        text_pull_refresh_header.setText("正在刷新");
        updateStatus(Status.REFRESHING);
    }

    private void releaseWithStatusLoadMore() {
        scrollTo(0, mEffictiveFooterHeight);
        text_pull_refresh_footer.setText("正在加载");
        progressbar_pull_refresh_footer.setVisibility(VISIBLE);
        updateStatus(Status.LOADING);
    }
  /*修改header和footer的状态*/
}
